package wsp.dailymarket.deals;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;
import javax.annotation.Resource;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.ArrayDataModel;
import javax.faces.model.DataModel;
import javax.sql.DataSource;
import wsp.dailymarket.auth.AuthenticationBean;
import wsp.dailymarket.obj.UserProfileBean;
import wsp.dailymarket.shopping.InvoiceDealCode;

/**
 * List of DealBeans
 * @author Matt
 */
@ManagedBean(name = "dealList")
@SessionScoped
public class DealListBean {

	@Resource(name = "jdbc/dmderby")
	private DataSource ds;
	@ManagedProperty(value = "#{authenticationBean}")
	private AuthenticationBean authBean;
	private boolean existingDeal;
	private boolean thisGuyHasDeals;
	private DealBean dealBean;
	private DataModel<DealBean> model;
	private ArrayList<InvoiceDealCode> codeList = new ArrayList<InvoiceDealCode>();
	private String filter_status;
	private static final String[] FILTERS_STATUS = {
		"starttime > CURRENT_TIMESTAMP", // Not Started
		"timed = 1 AND endtime < CURRENT_TIMESTAMP", // Ended
		"starttime < CURRENT_TIMESTAMP AND (timed = 0 OR endtime > CURRENT_TIMESTAMP)", // In Progress
	};

	public DealListBean() {
		this.dealBean = new DealBean();
		this.filter_status = FILTERS_STATUS[2];
	}

	public String doNewDeal() {
		this.dealBean = new DealBean(this.authBean.getAuthentication().getUserID(), this.authBean.getUserProfile().getDisplayName());
		this.existingDeal = false;
		return "deal_editor";
	}

	public String doManageDeal(DealBean theDeal) {
		this.setSingularDealId(theDeal.getID());
		return "manage_deal";
	}

	public String doEditDeal() {
		if (!this.dealBean.isLocked()) {
			this.existingDeal = true;
			return "deal_editor";
		} else {
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_ERROR);
			msg.setSummary("This deal is locked from changes because it is currently in progress!");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return null;
		}
	}

	public String getCancelEditDeal() {
		if (this.existingDeal) {
			return "manage_deal";
		} else {
			return "partner-deals";
		}
	}

	public String doSaveDeal() {
		// Check locked
		if (this.dealBean.isLocked()) {
			// This deal is locked, since changes may have been made and passed
			// to this bean, we will need to reload from the database
			this.setSingularDealId(this.dealBean.getID());
			// Take the user back to the manager and give them a nasty message
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_ERROR);
			msg.setSummary("This deal is locked from changes because it is currently in progress!");
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return "manage_deal";
		}

		// Save deal to database
		String sql = "";
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				if (this.existingDeal) {
					sql = "UPDATE APP.DEALS SET "
							+ "shortdesc = '"
							+ this.dealBean.getShortDesc()
							+ "', longdesc = '"
							+ this.dealBean.getLongDesc()
							+ "', minimumqty = "
							+ this.dealBean.getMinQty()
							+ ", maximumqty = "
							+ this.dealBean.getMaxQty()
							+ ", unitprice = "
							+ this.dealBean.getPrice()
							+ ", minuserqty = "
							+ this.dealBean.getMinUserQty()
							+ ", maxuserqty = "
							+ this.dealBean.getMaxUserQty()
							+ ", timed = "
							+ (this.dealBean.getTimed() ? "1" : "0")
							+ ", starttime = "
							+ (this.dealBean.getTimed() ? ("'" + new Timestamp(this.dealBean.getStartTime().getTime()).toString() + "'") : "CURRENT_TIMESTAMP")
							+ ", endtime = "
							+ (this.dealBean.getTimed() ? ("'" + new Timestamp(this.dealBean.getEndTime().getTime()).toString() + "'") : "NULL")
							+ ", default_image = "
							+ 0 // TODO Default image selection
							+ ", category_id = "
							+ this.dealBean.getCategory()
							+ " WHERE id="
							+ dealBean.getID();
				} else {
					sql = "INSERT INTO APP.DEALS (companyid, shortdesc, longdesc, minimumqty, maximumqty, unitprice, minuserqty, maxuserqty, timed, starttime, endtime, default_image, category_id) VALUES ('"
							+ authBean.getUserProfile().getEmailAddress()
							+ "', '"
							+ dealBean.getShortDesc()
							+ "', '"
							+ dealBean.getLongDesc()
							+ "', "
							+ dealBean.getMinQty()
							+ ", "
							+ dealBean.getMaxQty()
							+ ", "
							+ dealBean.getPrice()
							+ ", "
							+ dealBean.getMinUserQty()
							+ ", "
							+ dealBean.getMaxUserQty()
							+ ", "
							+ (dealBean.getTimed() ? "1" : "0")
							+ ", "
							+ (this.dealBean.getTimed() ? ("'" + new Timestamp(this.dealBean.getStartTime().getTime()).toString() + "'") : "CURRENT_TIMESTAMP")
							+ ", "
							+ (this.dealBean.getTimed() ? ("'" + new Timestamp(this.dealBean.getEndTime().getTime()).toString() + "'") : "NULL")
							+ ", "
							+ 0 // TODO Default image (image uploads)
							+ ", "
							+ dealBean.getCategory()
							+ ")";
				}
				if (stmt.executeUpdate(sql) == 1) {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_INFO);
					String errorMsg = authBean.getMessageBundle().getString("deal_manager_saveSuccess_" + (this.existingDeal ? "existing" : "new"));
					msg.setSummary(String.format(errorMsg, dealBean.getShortDesc()));
					FacesContext.getCurrentInstance().addMessage(null, msg);
				} else {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_ERROR);
					String errorMsg = authBean.getMessageBundle().getString("deal_manager_saveError_" + (this.existingDeal ? "existing" : "new"));
					msg.setSummary(String.format(errorMsg, dealBean.getShortDesc()));
					FacesContext.getCurrentInstance().addMessage(null, msg);
					return null;
				}
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			System.err.println(sql);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary(authBean.getMessageBundle().getString("database_error"));
			FacesContext.getCurrentInstance().addMessage(null, msg);
			return null;
		}
		return "partner-deals";
	}

	public String doDeleteDeal() {
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				String sql = "UPDATE APP.DEALS SET timed = 1, endtime = CURRENT_TIMESTAMP WHERE id = " + this.dealBean.getID();
				if (stmt.executeUpdate(sql) == 1) {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_INFO);
					msg.setSummary("Deal \"" + this.dealBean.getShortDesc() + "\" is now expired!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				} else {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_ERROR);
					msg.setSummary("The deal \"" + this.dealBean.getShortDesc() + "\" was not found!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				}
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException sql) {
			sql.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary(authBean.getMessageBundle().getString("database_error"));
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}
		return null;
	}

	public DataModel<DealBean> getDealList() {
		return model;
	}

	public boolean getRenderDealTable() throws SQLException {
		String sql = "SELECT APP.DEALS.*,APP.CLIENTS.COMPANYNAME,APP.CATEGORIES.CATEGORY_NAME FROM APP.DEALS INNER JOIN APP.CLIENTS ON APP.DEALS.COMPANYID=APP.CLIENTS.CLIENT_ID LEFT OUTER JOIN APP.CATEGORIES ON APP.DEALS.CATEGORY_ID = APP.CATEGORIES.ID ";
		boolean where_started = false;

		// If the user is an admin, list all deals, if they are a partner, list just their deals
		if (authBean.getAuthentication().getClientType() == UserProfileBean.CLIENT_TYPE_PARTNER) {
			sql += "WHERE companyid='" + authBean.getAuthentication().getUserID() + "' ";
			where_started = true;
		}

		// Filter by status
		if (!this.filter_status.isEmpty()) {
			if (where_started) {
				sql += "AND ";
			} else {
				sql += "WHERE ";
			}
			sql += this.filter_status;
		}

		// Build the model
		model = this.buildModel(sql);
		this.thisGuyHasDeals = model.getRowCount() > 0;
		return this.thisGuyHasDeals;
	}

	public String doShowInProgress() {
		this.filter_status = FILTERS_STATUS[2];
		return null;
	}

	public String getInProgressTabStyle() {
		if (this.filter_status.equals(FILTERS_STATUS[2])) {
			return "tab selected";
		}
		return "tab";
	}

	public String doShowEnded() {
		this.filter_status = FILTERS_STATUS[1];
		return null;
	}

	public String getEndedTabStyle() {
		if (this.filter_status.equals(FILTERS_STATUS[1])) {
			return "tab selected";
		}
		return "tab";
	}

	public String doShowNotStarted() {
		this.filter_status = FILTERS_STATUS[0];
		return null;
	}

	public String getNotStartedTabStyle() {
		if (this.filter_status.equals(FILTERS_STATUS[0])) {
			return "tab selected";
		}
		return "tab";
	}

	public String doShowAll() {
		this.filter_status = "";
		return null;
	}

	public String getAllTabStyle() {
		if ("".equals(this.filter_status)) {
			return "tab selected";
		}
		return "tab";
	}

	/**
	 * Used by the administrator deal moderation page
	 * @return All deals
	 * @throws SQLException On Database Error
	 */
	public DataModel<DealBean> getMasterDealList() throws SQLException {
		String sql = "SELECT APP.DEALS.*,APP.CLIENTS.COMPANYNAME,APP.CATEGORIES.CATEGORY_NAME FROM APP.DEALS INNER JOIN APP.CLIENTS ON APP.DEALS.COMPANYID=APP.CLIENTS.CLIENT_ID LEFT OUTER JOIN APP.CATEGORIES ON APP.DEALS.CATEGORY_ID = APP.CATEGORIES.ID";
		model = this.buildModel(sql);
		return model;
	}

	private DataModel<DealBean> buildModel(String sql) throws SQLException {
		return new ArrayDataModel<DealBean>(this.buildList(sql).toArray(new DealBean[0]));
	}

	private ArrayList<DealBean> buildList(String sql) throws SQLException {
		ArrayList<DealBean> dealList = new ArrayList<DealBean>();
		Connection conn = null;
		try {
			conn = ds.getConnection();
			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery(sql);
			while (rs.next()) {
				DealBean newDeal = new DealBean();
				newDeal.populate(
						rs.getInt("ID"),
						rs.getString("COMPANYID"),
						rs.getString("COMPANYNAME"),
						rs.getString("SHORTDESC"),
						rs.getString("LONGDESC"),
						rs.getFloat("UNITPRICE"),
						rs.getInt("MINIMUMQTY"),
						rs.getInt("MAXIMUMQTY"),
						rs.getInt("MINUSERQTY"),
						rs.getInt("MAXUSERQTY"),
						rs.getInt("TIMED") == 1,
						rs.getTimestamp("STARTTIME"),
						rs.getTimestamp("ENDTIME"),
						rs.getInt("DEFAULT_IMAGE"),
						rs.getInt("CATEGORY_ID"),
						rs.getString("CATEGORY_NAME"));
				dealList.add(newDeal);
			}
		} finally {
			if (conn != null) {
				conn.close();
			}
		}
		return dealList;
	}

	public void setAuthBean(AuthenticationBean newValue) {
		this.authBean = newValue;
	}

	public void setSingularDealId(int newValue) {
		this.dealBean = new DealBean();
		Connection conn = null;
		try {
			try {
				conn = ds.getConnection();
				Statement stmt = conn.createStatement();
				ResultSet rs = stmt.executeQuery("SELECT APP.DEALS.*,APP.CLIENTS.COMPANYNAME,APP.CATEGORIES.CATEGORY_NAME FROM APP.DEALS INNER JOIN APP.CLIENTS ON APP.DEALS.COMPANYID=APP.CLIENTS.CLIENT_ID LEFT OUTER JOIN APP.CATEGORIES ON APP.DEALS.CATEGORY_ID = APP.CATEGORIES.ID WHERE APP.DEALS.ID=" + newValue);
				if (rs.next()) {
					dealBean.populate(
							rs.getInt("ID"),
							rs.getString("COMPANYID"),
							rs.getString("COMPANYNAME"),
							rs.getString("SHORTDESC"),
							rs.getString("LONGDESC"),
							rs.getFloat("UNITPRICE"),
							rs.getInt("MINIMUMQTY"),
							rs.getInt("MAXIMUMQTY"),
							rs.getInt("MINUSERQTY"),
							rs.getInt("MAXUSERQTY"),
							rs.getInt("TIMED") == 1,
							rs.getTimestamp("STARTTIME"),
							rs.getTimestamp("ENDTIME"),
							rs.getInt("DEFAULT_IMAGE"),
							rs.getInt("CATEGORY_ID"),
							rs.getString("CATEGORY_NAME"));
					dealBean.setLocked(dealBean.getStartTime().before(new Date()));
					dealBean.populateImages(conn);
				} else {
					FacesMessage msg = new FacesMessage();
					msg.setSeverity(FacesMessage.SEVERITY_ERROR);
					msg.setSummary("This deal no longer exists!");
					FacesContext.getCurrentInstance().addMessage(null, msg);
				}
			} finally {
				if (conn != null) {
					conn.close();
				}
			}
		} catch (SQLException ex) {
			ex.printStackTrace(System.err);
			FacesMessage msg = new FacesMessage();
			msg.setSeverity(FacesMessage.SEVERITY_FATAL);
			msg.setSummary("Database Error");
			FacesContext.getCurrentInstance().addMessage(null, msg);
		}
	}

	public int getSingularDealId() {
		return this.dealBean.getID();
	}

	public DealBean getDealBean() {
		return this.dealBean;
	}

	public boolean isExistingDeal() {
		return this.existingDeal;
	}

	public TimeZone getTimeZone() {
		return TimeZone.getDefault();
	}

	public boolean getHasDeals() {
		return this.thisGuyHasDeals;
	}
}
